
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011-2023 Anlogic, Inc.
// All Right Reserved.
///////////////////////////////////////////////////////////////////////////////
//
//
//   Vendor : Anlogic
//   Version : 1.0
//   Description : 
//   Filename : uart_tx.v
//   Timestamp :
//
///////////////////////////////////////////////////////////////////////////////
//
// Revision:
//    2023/01/03 - 1.0 - Initial version.
//
///////////////////////////////////////////////////////////////////////////////

`timescale  1 ps / 1 ps

module  uart_tx
#(
    parameter       UART_BPS    =   'd9600      ,
    parameter       CLK_FREQ    =   'd50_000_000
)
(
input        wire          sys_clk  ,
input        wire          uart_clk ,
input        wire          sys_rst_n,
input        wire   [7:0]  in_data  , 
input        wire          in_flag  ,
 
output       reg           tx,    
output       reg           done       
);
 
parameter   BAUD_CNT_MAX    =   CLK_FREQ / UART_BPS;
 
reg             tx_done;
reg             work_en;
reg   [16:0]    baud_cnt;
reg   [3:0]     bit_cnt;
reg             bit_flag;

reg   [7:0]     in_data_l;

always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        in_data_l <= 'b0; 
    else if(in_flag)
        in_data_l <= in_data;
 
always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        work_en <= 1'b0;
    else if(in_flag == 1'b1)
        work_en <= 1'b1;
    else if((bit_cnt == 4'd9)&&(bit_flag == 1'b1))
        work_en <= 1'b0;
    else
        work_en <= work_en;
 
always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        baud_cnt <= 16'd0;
    else if((baud_cnt == BAUD_CNT_MAX - 1'b1)||(work_en == 1'b0))
        baud_cnt <= 16'd0;
    else if(work_en == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;
 
always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_flag <= 1'b0;
    else if(baud_cnt == 16'd1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;
 
always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'd0;
    else if((bit_cnt == 4'd9)&&(bit_flag == 1'b1))
        bit_cnt <= 4'd0;
    else if((bit_flag == 1'b1)&&(work_en == 1'b1))
        bit_cnt <= bit_cnt + 1'b1;
    else
        bit_cnt <= bit_cnt;

always@(posedge uart_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        tx_done <= 1'b0;
    else if((bit_cnt == 4'd9)&&(bit_flag == 1'b1))
        tx_done <= 1'b1;
    else
        tx_done <= 1'b0;

always@(posedge uart_clk or  negedge sys_rst_n) begin
    if(sys_rst_n == 1'b0) begin
        tx <= 1'b1;  
    end
    else if(bit_flag == 1'b1) begin
        case(bit_cnt)
            0:  tx <= 1'b0;     
            1:  tx <= in_data_l[0];
            2:  tx <= in_data_l[1];
            3:  tx <= in_data_l[2];
            4:  tx <= in_data_l[3];
            5:  tx <= in_data_l[4];
            6:  tx <= in_data_l[5];
            7:  tx <= in_data_l[6];
            8:  tx <= in_data_l[7];
            9:  tx <= 1'b1;        
            default: tx = 1'b1;
        endcase
    end
end

///////////////////////////////////////////////////////////////

reg  tx_data_done_flg;
reg  tx_data_done_flg_sync1;
reg  tx_data_done_flg_sync2;
reg  tx_data_done_flg_sync3; 

     
always @(posedge uart_clk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        tx_data_done_flg <= 'h0;
    else if(done)
        tx_data_done_flg <= 'h0;
    else if(tx_done)
        tx_data_done_flg <= 'h1;
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin 
        tx_data_done_flg_sync1 <= 'h0; 
        tx_data_done_flg_sync2 <= 'h0; 
        tx_data_done_flg_sync3 <= 'h0; 
    end 
    else begin 
        tx_data_done_flg_sync1 <= tx_data_done_flg;
        tx_data_done_flg_sync2 <= tx_data_done_flg_sync1; 
        tx_data_done_flg_sync3 <= tx_data_done_flg_sync2; 
    end 
end

always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin 
        done <= 'h0;  
    end 
    else begin 
        done <= (tx_data_done_flg_sync2 & (~tx_data_done_flg_sync3)); 
    end 
end
  
endmodule
